using System;
using System.ComponentModel;
using System.ComponentModel.Design;

using System.Drawing;
using System.Drawing.Drawing2D;

namespace Camalon.Drawing
{
	public enum PathGradientFillMode
	{
		Default,
		Flatten,
		Elliptic
	}

	[ToolboxItem( true )]
	[ToolboxBitmap( typeof( ShapePen ), "Components.PathGradientFill.bmp")]
    [Designer("Camalon.Drawing.Design.PathGradientFillDesigner, Camalon.Drawing.Design", typeof(IDesigner))]
    public class PathGradientFill : MulticolorFill
	{
		private SizeScale				_focusScale;
		private PointScale				_centerScale;
		private PathGradientFillMode	_fillMode;
	

		public PathGradientFill():base(FillType.PathGradient)
		{
			_focusScale		= SizeScale.Empty;
			_centerScale	= PointScale.Center;
			_fillMode		= PathGradientFillMode.Default;

		}

		private GraphicsPath TilePath( GraphicsPath path )
		{
			if( path == null) return null;

			try
			{
				FillTile tile = base.Tile;
				if( tile.IsEmpty ) return path;

				RectangleF b = path.GetBounds();

				float scaleX = 1f;
				float scaleY = 1f;
			
				if( tile.TileRelative)
				{
					scaleX = tile.TileX <=0 ? 1f:(float)tile.TileX/100f;
					scaleY = tile.TileY <=0 ? 1f:(float)tile.TileY/100f;
				}
				else
				{
					scaleX = tile.TileX <=0 ? 1f:(float)tile.TileX/b.Width;
					scaleY = tile.TileY <=0 ? 1f:(float)tile.TileY/b.Height;
				}

				if( scaleX == 1f && scaleY == 1f ) return path;

				GraphicsPath p = path.Clone() as GraphicsPath;
				p.FillMode = path.FillMode;

				using( Matrix m = new Matrix())
				{
					m.Scale( scaleX, scaleY);

					PointF p2 = b.Location;
					PointF p1 = p.GetBounds(m).Location;

					if( p1 != p2)
					{
						float dx = p2.X - p1.X;
						float dy = p2.Y - p1.Y;
						m.Translate( dx,dy, MatrixOrder.Append );
					}
					

					p.Transform( m );
				}


				return p;
			}
			catch ( Exception e)
			{
				FileWatcher.WriteLine( "TilePath failed" + e.StackTrace);
				return path;
			}
		}


		public Brush GetBrush( GraphicsPath path )
		{
			if( path == null) return null;

			GraphicsPath gp = TilePath( path );
			
			PathGradientBrush brush		= new PathGradientBrush( gp );
			brush.WrapMode				= base.WrapMode;
			brush.FocusScales			= _focusScale.Point;
			brush.CenterPoint			= this.CenterPoint(gp.GetBounds());
			if( base.Blend != null)		brush.InterpolationColors	= base.Blend;

			return brush;
			
		}


		public Brush GetBrush( RectangleF bounds )
		{
			if( bounds.IsEmpty) return null;

			using(GraphicsPath path = new GraphicsPath())
			{
				bounds = TileBounds( bounds );

				if( _fillMode == PathGradientFillMode.Elliptic ) path.AddEllipse( MakeEllipticBounds( bounds ) );
				else path.AddRectangle( bounds );

				PathGradientBrush brush		= new PathGradientBrush( path );
				brush.WrapMode				= base.WrapMode;
				brush.FocusScales			= _focusScale.Point;
				brush.CenterPoint			= this.CenterPoint(path.GetBounds());
				if( base.Blend != null)		brush.InterpolationColors	= base.Blend;
				

				return brush;
			}
		}


		internal RectangleF MakeEllipticBounds( RectangleF bounds )
		{
			if( !base.Tile .IsEmpty) return bounds;
			//To make a elliptic bounds
			//----------------------------------------------------------------
			//			***************************
			//			*						  *
			//			*						  *
			//			*		  (0)	   w	  *
			//			*           ***************
			//			*			*  *		  *
			//			*		  h	*      a	  *
			//			*			*	       *  *
			//			*************************** P(x,y) = P( w, h)
			//							  	
			// (x^2/a^2) + (y^2/b^2)= 1 ==> b^2 = ( a^2 * y^2)/(a^2 - x^2)
			// with: a^2 = h^2 + w^2
			//----------------------------------------------------------------
			float w  = bounds.Width / 2f;	float w2 = w * w;
			float h  = bounds.Height / 2f;	float h2 = h * h;
			float a2 = w2 + h2;			
			float a  = (float)System.Math.Sqrt( a2 );
			float b = (float)System.Math.Sqrt( (a2*h2) / (a2 - w2) );
			bounds.Inflate( a-w, b-h);

			return bounds;
		}


		[DefaultValue(typeof(SizeScale),"Empty")]
		[RefreshProperties(RefreshProperties.All)]
		[Category("Style")]
		public SizeScale FocusScale
		{
			get{ return _focusScale;}
			set
			{
				if( _focusScale.Equals( value )) return;
				if( value.Width > 1f) value.Width = 1f;
				if( value.Width < 0f) value.Width = 0f;
				if( value.Height > 1f) value.Height = 1f;
				if( value.Height < 0f) value.Height = 0f;

				_focusScale = value;
				InvokeInternalChanged();
			}
		}

		[DefaultValue(typeof(PointScale),"Center")]
		[RefreshProperties(RefreshProperties.All)]
		[Category("Style")]
		public PointScale CenterScale
		{
			get{ return _centerScale;}
			set
			{
				if( _centerScale.Equals( value )) return;

				_centerScale = value;
				InvokeInternalChanged();
			} 
		}


		[DefaultValue(PathGradientFillMode.Default)]
		[RefreshProperties(RefreshProperties.All)]
		[Category("Style")]
		public PathGradientFillMode FillMode
		{
			get{ return _fillMode;}
			set
			{
				if( _fillMode == value ) return;
				_fillMode = value;
				InvokeInternalChanged();
			} 
		}

		public static PointF ScalePoint( RectangleF bounds , PointScale scale)
		{
			float x = bounds.Width  * scale.X;
			float y = bounds.Height * scale.Y;

			PointF pt = bounds.Location;
			pt.X+= x;
			pt.Y+= y;

			return pt;
		}

	
		public PointF CenterPoint( RectangleF bounds )
		{
			return ScalePoint( bounds, _centerScale);
		}


//		CompoundColor _compoundColor = CompoundColor.Empty;
//
//		[DefaultValue( typeof(CompoundColor),"Empty")]
//		public CompoundColor CompoundColor
//		{
//			get{ return _compoundColor;}
//			set{ _compoundColor = value;}
//		}

	}
}
